package net.gldwork.mybatisext.util;

import java.util.Map;

import org.apache.ibatis.mapping.BoundSql;

public class PrepareSqlUtil {
    private static final String DRIVERTYPE_MYSQL = "mysql";
    private static final String DRIVERTYPE_SQLSERVER = "sqlserver";
    private static final String DRIVERTYPE_ORACLE = "oracle";
    public static String driverType = DRIVERTYPE_SQLSERVER;
    public static final String DATAPRIVILEGE_PRE = "_dataPrivilegePre";
    public static final String DATAPRIVILEGE_POST = "_dataPrivilegePost";
    public static final String AUTOPAGING_FLAG = "_mybatisAutoPagingFlag";

    @SuppressWarnings("rawtypes")
    private static String appendPrivilege(String sql, Map mapP) {
        String dataPrivilegePre = (String) mapP.get(DATAPRIVILEGE_PRE);
        String dataPrivilegePost = (String) mapP.get(DATAPRIVILEGE_POST);
        if (dataPrivilegePre != null || dataPrivilegePost != null) {
            StringBuffer sbp = new StringBuffer();
            if (dataPrivilegePre != null) {
                sbp.append(dataPrivilegePre);
            }
            sbp.append(sql);
            if (dataPrivilegePost != null) {
                sbp.append(dataPrivilegePost);
            }
            sql = sbp.toString();
        }
        return sql;
    }

    @SuppressWarnings("rawtypes")
    public static String prepare(BoundSql boundSql) {

        String sql = boundSql.getSql();
        Object param = boundSql.getParameterObject();
        // 限制为只当参数是map时才执行
        if (param instanceof Map) {
            Map mapP = (Map) param;
            Boolean autoPaging = (Boolean) mapP.get(AUTOPAGING_FLAG);
            if (autoPaging != null && autoPaging) {
                Integer start = (Integer) mapP.get("start");
                Integer limit = (Integer) mapP.get("limit");
                if (start != null && limit != null) {

                    if (DRIVERTYPE_MYSQL.equals(driverType)) {
                        sql = appendPrivilege(sql, mapP);
                        StringBuffer sb = new StringBuffer();
                        sb.append(sql).append(" limit ").append(start)
                                .append(",").append(limit);
                        sql = sb.toString();
                    } else if (DRIVERTYPE_SQLSERVER.equals(driverType)) {
                        StringBuffer sb = new StringBuffer();
                        int orderByIndex = sql.toLowerCase().lastIndexOf(
                                "order by");
                        String orderByStr = null;
                        if (orderByIndex <= 0) {
                            orderByStr = "order by (select 0)";
                        } else {
                            orderByStr = sql.substring(orderByIndex);
                            orderByStr = orderByStr.replaceAll("\\s\\w+\\.",
                                    " ");
                            sql = sql.substring(0, orderByIndex - 1);
                        }
                        sql = appendPrivilege(sql, mapP);
                        sb.append("WITH query AS (select ROW_NUMBER() OVER (")
                                .append(orderByStr)
                                .append(") as _mybatis_rn,AA.* from (");
                        sb.append(sql)
                                .append(") AA) SELECT * FROM query WHERE _mybatis_rn BETWEEN ")
                                .append(start).append(" AND ")
                                .append(start + limit);
                        sql = sb.toString();
                    } else if (DRIVERTYPE_ORACLE.equals(driverType)) {
                        sql = appendPrivilege(sql, mapP);
                        StringBuffer sb = new StringBuffer();
                        if (start > 0) {
                            sb.append("select * from ( select row_.*, rownum rownum_ from ( ");
                        } else {
                            sb.append("select * from ( ");
                        }
                        sb.append(sql);
                        if (start > 0) {
                            sb.append(" ) row_ where rownum <= ")
                                    .append(start + limit)
                                    .append(") where rownum_ > ").append(start);
                        } else {
                            sb.append(" ) where rownum <= ").append(limit);
                        }
                        sql = sb.toString();
                    }

                } else {
                    sql = appendPrivilege(sql, mapP);
                }
            } else {
                sql = appendPrivilege(sql, mapP);
            }
        }

        return sql;
    }
}
